#include <iostream>
#include <mutex>
#include <pthread.h>
#define NUM_THREADS 5 // 线程个数

// 饿汉实现
class Singleton {
    public:

    // 获取单实例
    static Singleton* GetInstance();

    // 释放单实例，进程退出时调用
    static void deleteInstance();

    // 打印实例地址
    void Print();

    private:
    // 私有构造和析构函数，禁止外部构造和析构
    Singleton();
    ~Singleton();

    // 将其拷贝构造和赋值拷贝构造成为私有函数，禁止外部拷贝和赋值
    Singleton(const Singleton &signal);
    const Singleton &operator=(const Singleton &signal);

    private:
    static Singleton* g_pSingleton;
};

// 代码一运行就初始化创建实例，本身就线程安全
Singleton* Singleton::g_pSingleton = new (std::nothrow) Singleton;

Singleton* Singleton::GetInstance() {
    return g_pSingleton;
}

void Singleton::deleteInstance() {
    if(g_pSingleton) {
        delete g_pSingleton;
        g_pSingleton = nullptr;
    }
}

void Singleton::Print() {
    std::cout << "我的实例内存地址是" << this << std::endl;
}

Singleton::Singleton() {
    std::cout << "构造函数" << std::endl;
}

Singleton::~Singleton() {
    std::cout << "析构函数" << std::endl;
}


// 线程函数
void* PrintHello(void* threadid) {
    // 主线程与子线程分离，两者相互不干涉，子线程结束同时子线程的资源自动回收
    pthread_detach(pthread_self());

    // 对传入的参数进行强制类型转换，由无类型指针变为整数型指针，然后再读取
    int tid = *((int*)threadid);

    std::cout << "Hi,我是线程 ID:[" << tid << "]" << std::endl;

    // 打印实例地址
    Singleton::GetInstance()->Print();

    pthread_exit(nullptr);
}


int main () {
    std::cout << "hello 饿汉式单例模式!!" << std::endl;
    pthread_t threads[NUM_THREADS] = {0};
    int indexes[NUM_THREADS] = {0};

    int ret = 0;
    int i = 0;

    std::cout << "main() : 开始 ... " << std::endl;

    for(i = 0;i < NUM_THREADS;i++) {
        std::cout << "main() : 创建线程：[" << i << "]" << std::endl;

        indexes[i] = i;  // 先保存i的值

        // 传入的时候必须强制转换为void*类型，及无类型指针
        ret = pthread_create(&threads[i],NULL,PrintHello,(void*)&(indexes[i]));

        if(ret) {
            std::cout << "Error:无法创建线程，" << ret << std::endl;
            exit(-1);
        }
    }

    // 手动释放单实例的资源
    Singleton::deleteInstance();
    std::cout << "main() : 结束！" << std::endl;

    return 0;
}